﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace DARE
{
    /// <summary>
    /// Base-class for every type of sky. See SkyBox, SkyDome, SkyPlane.
    /// </summary>
    public abstract class ASky
    {

        #region fields

        protected Texture m_texture;
        protected Effect m_effect;
        protected string m_technique;
        protected string m_name;
        protected CRender3D m_render3D;
        protected Vector3 m_scale;
        protected VertexBuffer m_vertexBuffer;
        protected IndexBuffer m_indexBuffer;
        protected RasterizerState m_rasterizer;

        #endregion

        #region properties

        public string Name
        {
            get { return m_name; }
            set { m_name = value; }
        }

        public Texture Texture
        {
            get { return m_texture; }
            set { m_texture = value;  }
        }

        public string TextureName
        {
            get { return m_texture.Name; }
            set
            {
                Texture = DARE.CResourceMgr.Load<TextureCube>(value);
                Texture.Name = value;
            }
        }

        public Vector3 Distance
        {
            get { return m_scale; }
            set { m_scale = value; }
        }

        public Effect Effect
        {
            get { return m_effect; }
        }

        public FillMode FillMode
        {
            get { return m_rasterizer.FillMode; }
            set
            {
                if (value != m_rasterizer.FillMode)
                {
                    CullMode cullMode = m_rasterizer.CullMode;

                    m_rasterizer = new RasterizerState();
                    m_rasterizer.FillMode = value;
                    m_rasterizer.CullMode = cullMode;
                }
            }
        }

        public CullMode CullMode
        {
            get { return m_rasterizer.CullMode; }
            set
            {
                if (value != m_rasterizer.CullMode)
                {
                    FillMode fillMode = m_rasterizer.FillMode;

                    m_rasterizer = new RasterizerState();
                    m_rasterizer.FillMode = fillMode;
                    m_rasterizer.CullMode = value;
                }
            }
        }

        #endregion

        #region ctor

        protected void ctor(CRender3D render3D)
        {
            m_render3D = render3D;
            m_scale = Vector3.One * 30f;
            CreateModel(out m_vertexBuffer, out m_indexBuffer);
            m_rasterizer = new RasterizerState();
        }

        public ASky(CRender3D render3D)
        {
            ctor(render3D);
        }

        #endregion

        #region methods

        protected abstract void CreateModel(out VertexBuffer vb, out IndexBuffer ib);

        #endregion

        #region run

        public void Update(GameTime gameTime)
        {
            
        }

        public void Draw(GameTime gameTime)
        {
            if (m_render3D == null)
                return;
            if (m_render3D.CameraMgr.ActiveCamera == null)
                return;

            CDare.Instance.GraphicsDevice.RasterizerState = m_rasterizer;
            CDare.Instance.GraphicsDevice.DepthStencilState = DepthStencilState.None;

#if !WINDOWS_PHONE

            m_effect.CurrentTechnique = m_effect.Techniques[m_technique];
            m_effect.Parameters["posEye"].SetValue(m_render3D.CameraMgr.ActiveCamera.Position);
            m_effect.Parameters["Map"].SetValue(m_texture);
            foreach (EffectPass pass in m_effect.CurrentTechnique.Passes)
            {
                Matrix World = Matrix.CreateScale(m_scale) * Matrix.CreateTranslation(m_render3D.CameraMgr.ActiveCamera.Position);
                m_effect.Parameters["matWorld"].SetValue(World);
                m_effect.Parameters["matWorldViewProj"].SetValue(World *  m_render3D.CameraMgr.ActiveCamera.View * m_render3D.CameraMgr.ActiveCamera.Projection);
                pass.Apply();
                CDare.Instance.GraphicsDevice.SetVertexBuffer(m_vertexBuffer);
                CDare.Instance.GraphicsDevice.Indices = m_indexBuffer;
                CDare.Instance.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 8, 0, 12);
            }

#else
            EnvironmentMapEffect e = m_effect as EnvironmentMapEffect;
            e.EnvironmentMap = m_texture as TextureCube;
            foreach (EffectPass pass in m_effect.CurrentTechnique.Passes)
            {
                Matrix World = Matrix.CreateScale(m_scale) * Matrix.CreateTranslation(m_render3D.CameraMgr.ActiveCamera.Position);
                e.World = World;
                e.View = m_render3D.CameraMgr.ActiveCamera.View;
                e.Projection = m_render3D.CameraMgr.ActiveCamera.Projection;
                pass.Apply();
                CDare.Instance.GraphicsDevice.SetVertexBuffer(m_vertexBuffer);
                CDare.Instance.GraphicsDevice.Indices = m_indexBuffer;
                CDare.Instance.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 8, 0, 12);
            }
#endif

            CDare.Instance.GraphicsDevice.DepthStencilState = DepthStencilState.Default;

        }

        #endregion

    }
}
